﻿using UnityEngine;
using System;
using System.Collections;

public class ServerPrimary : MonoSingleton<ServerPrimary> {
	
	public enum GameState {
		OFFLINE,
		QUEUING,
		MAPPING,
		ENTERING,
	}
	private GameState currentState;
	public GameState CurrentState {
		get {
			return currentState;
		}

		set {
			if (value == currentState)
				return;

			currentState = value;

			switch(value) {
			case GameState.OFFLINE:
				foreach (NetworkPlayer p in Network.connections)
					Network.CloseConnection (p, true);
				
				Network.maxConnections = 0;
				
				Application.LoadLevel("SceneOpeningMenu");
				break;

			case GameState.QUEUING:
				break;
			
			case GameState.MAPPING:
				Debug.Log ("GameState: MAPPING");
				Application.LoadLevel("SceneGameArena");
				break;

			case GameState.ENTERING:
				Transform mySpawnPoint = Dungeon.instance.ServerSpawn.transform;
				CreateGameObject (MODEL_AVATAR, mySpawnPoint.position, mySpawnPoint.rotation);
				CreateGameObject (MODEL_GOAL_ITEM1, Dungeon.instance.GoalItem1Spawn, Quaternion.identity);
				CreateGameObject (MODEL_GOAL_ITEM2, Dungeon.instance.GoalItem2Spawn, Quaternion.identity);
				CreateGameObject (MODEL_GOAL_ITEM3, Dungeon.instance.GoalItem3Spawn, Quaternion.identity);

				networkView.RPC("OnClientMapped", RPCMode.Server, Network.player);
				break;

			default:
				break;
			}
		}
	} // end property

	public const int MAX_CONNECTIONS = 32;
	public const int MODEL_AVATAR = 0;
	public const int MODEL_PING = 1;
	public const int MODEL_GOAL_ITEM1 = 2;
	public const int MODEL_GOAL_ITEM2 = 3;
	public const int MODEL_GOAL_ITEM3 = 4;

	public GameObject playerPrefab;
	public GameObject pingPrefab;
	public GameObject goalItem1Prefab;
	public GameObject goalItem2Prefab;
	public GameObject goalItem3Prefab;

	public Vector3 goalItem1Position;
	public Vector3 goalItem2Position;
	public Vector3 goalItem3Position;

	private bool isOpen = false;
	public bool IsOpen {
		get {
			return isOpen;
		} // end getter

		set {
			isOpen = value;

			if (true == value) {
				Network.maxConnections = MAX_CONNECTIONS;
				CurrentState = GameState.QUEUING;				
				return;
			}

			CurrentState = GameState.OFFLINE;
		} // end setter
	} // end property

	public bool HasOpened { get; set; }

	[RPC]
	public void CreateGameObject(int typeID, Vector3 position, Quaternion rotation) {
		GameObject objectToCreate = null;
		
		Debug.Log("CreateGameObject: " + typeID);
		
		switch (typeID) {
		case MODEL_AVATAR:
			objectToCreate = playerPrefab;
			break;
		case MODEL_PING:
			objectToCreate = pingPrefab;
			break;
		case MODEL_GOAL_ITEM1:
			objectToCreate = goalItem1Prefab;
			goalItem1Position = position;
			break;
		case MODEL_GOAL_ITEM2:
			objectToCreate = goalItem2Prefab;
			goalItem2Position = position;
			break;
		case MODEL_GOAL_ITEM3:
			objectToCreate = goalItem3Prefab;
			goalItem3Position = position;
			break;

		default:
			// TODO: error condition
			return;
		} // end switch: translate enumeration into prefab
		
		GameObject newGameObject = (GameObject)Network.Instantiate (objectToCreate, position, rotation, typeID);
		if (objectToCreate == playerPrefab)
			newGameObject.networkView.RPC ("SetPlayer", RPCMode.AllBuffered, Network.player);
		//networkView.RPC ("registerGameObject", RPCMode.Server, newGameObject.networkView.viewID);
	} // end RPC

	void Awake() {
		this.HasOpened = false;
		Application.runInBackground = true;
		DontDestroyOnLoad (transform.root.gameObject); // persist this object through all scenes
	} // end initializer

	[RPC]
	public void OnDungeonReady(Dungeon d) {
		Debug.Log ("OnDungeonReady: " + d.Seed);

		if (Network.isServer) {
			networkView.RPC("LoadMap", RPCMode.OthersBuffered, d.Seed);
		} else {
			Transform mySpawnPoint = d.ClientSpawn.transform;
			CreateGameObject (MODEL_AVATAR, mySpawnPoint.position, mySpawnPoint.rotation);
			networkView.RPC("OnClientMapped", RPCMode.Server, Network.player);
		}

	} // end custom event

	[RPC]
	public void OnClientMapped(NetworkPlayer player) {
		if (Network.isServer) {
			CurrentState = GameState.ENTERING;
		} else
			return; // Error condition: This is a client-only RPC.
	} // end custom event

	[RPC]
	public void LoadMap(int seed) {
		Debug.Log("LoadMap ordered from server: " + seed);

		if (Network.isClient) {
			Dungeon.instance.Seed = seed;
			CurrentState = GameState.MAPPING;
		} else
			return; // Error condition: This is a client-only RPC.
	} // end RPC

	void OnLevelWasLoaded(int level) {
		if (0 == level)
			this.IsOpen = false;
	} // end event

	void OnServerInitialized()
	{
		Debug.Log ("Server initialized locally.");
		this.HasOpened = true;
	} // end event

	void OnPlayerConnected(NetworkPlayer player)
	{
		Debug.Log ("Remote player connection: " + player.ToString ());
	} // end event
	
	void OnPlayerDisconnected(NetworkPlayer player) {
		Debug.Log("Clean up after player " +  player);
		Network.RemoveRPCs(player);
		Network.DestroyPlayerObjects(player);
	} // end event

	void OnDisconnectedFromServer(NetworkDisconnection info) {
		Debug.Log ("Disconnected from server.");
		CurrentState = GameState.OFFLINE;
	} // end event
}
